/*
* Copyright (C) 2008-2009 J-P Nurmi jpnurmi@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* $Id: mainwindow.cpp 401 2009-05-10 09:58:00Z jpnurmi $
*/

#include "mainwindow.h"
#include "connectdialog.h"
#include "sessiontabwidget.h"
#include "maintabwidget.h"
#include "connection.h"
#include "ircmodel.h"
#include "homeview.h"
#include <ircsession.h>
#include <QtGui>
#ifndef QT_NO_OPENSSL
#include <QSslSocket>
#endif // QT_NO_OPENSSL

MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), startup(true)
{
    setWindowFilePath(tr("Welcome"));

    tabWidget = new MainTabWidget(this);
    tabWidget->setFocusPolicy(Qt::NoFocus);
    setCentralWidget(tabWidget);

    model = new IrcModel(this);

    if (QSystemTrayIcon::isSystemTrayAvailable())
    {
        trayIcon = new TrayIcon(this);
        trayIcon->setIcon(QApplication::windowIcon());
        trayIcon->setVisible(true);
        connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
            this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason)));
    }

    QShortcut* shortcut = new QShortcut(QKeySequence::ZoomIn, this);
    connect(shortcut, SIGNAL(activated()), this, SLOT(zoomIn()));

    shortcut = new QShortcut(QKeySequence::ZoomOut, this);
    connect(shortcut, SIGNAL(activated()), this, SLOT(zoomOut()));
    
    shortcut = new QShortcut(QKeySequence(tr("Ctrl+Q")), this);
    connect(shortcut, SIGNAL(activated()), this, SLOT(close()));
    
    QSettings settings;
    settings.beginGroup("State");
    if (!restoreGeometry(settings.value("geometry").toByteArray()))
        resize(800, 600);

    HomeView* homeView = new HomeView(tabWidget);
    connect(homeView, SIGNAL(connectTo(QString, quint16, QString, QString)), 
        this, SLOT(connectTo(QString, quint16, QString, QString)));
    tabWidget->addTab(homeView, tr("Home"));

    QTimer::singleShot(0, this, SLOT(initialize()));
}

void MainWindow::closeEvent(QCloseEvent* event)
{
    QSettings settings;
    settings.beginGroup("State");
    settings.setValue("geometry", saveGeometry());

    uint key = -1;
    SessionTabWidget* currentTab = qobject_cast<SessionTabWidget*>(tabWidget->currentWidget());
    if (currentTab)
        key = currentTab->hashKey();
    settings.setValue("current", key);

    for (int i = 0; i < tabWidget->count(); ++i)
    {
        SessionTabWidget* tab = qobject_cast<SessionTabWidget*>(tabWidget->widget(i));
        if (tab)
            tab->save();
    }

    QMainWindow::closeEvent(event);
}

void MainWindow::changeEvent(QEvent* event)
{
    QMainWindow::changeEvent(event);
    if (event->type() == QEvent::ActivationChange)
    {
        if (isActiveWindow())
            trayIcon->unalert();
    }
}

void MainWindow::initialize()
{
    Connection tmp; // TODO: needed to register meta type stream opers
    bool autoConnected = false;
    foreach (const Connection& connection, Connection::connections())
    {
        if (connection.autoConnect)
        {
            connectToImpl(connection);
            autoConnected = true;
        }
    }

    if (!autoConnected && !connectTo(QString(), 6667, QString(), QString()))
        close();

    startup = false;
}

bool MainWindow::connectTo(const QString& host, quint16 port, const QString& password, const QString& nick)
{
    ConnectDialog dialog;
    Connection connection;
    if (!host.isEmpty())
        connection.host = host;
    if (port != 6667)
        connection.port = port;
    if (!password.isEmpty())
        connection.pass = password;
    if (!nick.isEmpty())
        connection.nick = nick;

    if (dialog.exec())
    {
        connectToImpl(dialog.connection());
        return true;
    }
    return false;
}

void MainWindow::connectToImpl(const Connection& connection)
{
    Irc::Session* session = new Irc::Session(this);
#ifndef QT_NO_OPENSSL
    if (connection.secure)
    {
        QSslSocket* socket = new QSslSocket(session);
        socket->setPeerVerifyMode(QSslSocket::VerifyNone);
        socket->ignoreSslErrors();
        session->setSocket(socket);
    }
#endif // QT_NO_OPENSSL
    connect(session, SIGNAL(connected()), this, SLOT(connected()));
    connect(session, SIGNAL(disconnected()), this, SLOT(disconnected()));
    session->setAutoReconnectDelay(10);
    session->setOptions(Irc::Session::StripNicks);
    QString appName = QApplication::applicationName();
    session->setNick(connection.nick);
    session->setIdent(appName.toLower());
    session->setRealName(connection.real.isEmpty() ? appName : connection.real);
    session->setPassword(connection.pass);
    session->connectToServer(connection.host, connection.port);

    SessionTabWidget* tab = new SessionTabWidget(session, model, tabWidget);
    connect(tab, SIGNAL(alertStarted()), this, SLOT(alert()));
    connect(tab, SIGNAL(connectTo(QString, quint16, QString, QString)), this, SLOT(connectTo(QString, quint16, QString, QString)));
    connect(tab, SIGNAL(connectToImpl(Connection)), this, SLOT(connectToImpl(Connection)));
    connect(tab, SIGNAL(disconnectFrom(QString)), this, SLOT(disconnectFrom(QString)));
    connect(tab, SIGNAL(quit(QString)), this, SLOT(quit(QString)));
    int index = tabWidget->addTab(tab, session->host());
    tabWidget->setTabEnabled(index, false);
    if (!startup)
    {
        tabWidget->setCurrentWidget(tab);
    }
    else
    {
        QTimer* timer = new QTimer(tab);
        timer->setSingleShot(true);
        timer->setInterval(1000);
        connect(timer, SIGNAL(timeout()), timer, SLOT(deleteLater()));
        connect(timer, SIGNAL(destroyed()), tab, SLOT(restore()));

        // trigger by first connect
        connect(session, SIGNAL(connected()), timer, SLOT(start()));

        QSettings settings;
        settings.beginGroup("State");
        uint key = settings.value("current", -1).toUInt();
        if (key == tab->hashKey())
            tabWidget->setCurrentWidget(tab);
    }
}

void MainWindow::disconnectFrom(const QString& message)
{
    SessionTabWidget* tab = qobject_cast<SessionTabWidget*>(sender());
    Q_ASSERT(tab);
    tab->session()->cmdQuit(message);
    tab->session()->disconnectFromServer();
}

void MainWindow::quit(const QString& message)
{
    // TODO: confirm?
    for (int i = 0; i < tabWidget->count(); ++i)
    {
        SessionTabWidget* tab = qobject_cast<SessionTabWidget*>(tabWidget->widget(i));
        tab->session()->cmdQuit(message);
        tab->session()->disconnectFromServer();
    }
    close();
}

void MainWindow::connected()
{
    for (int i = 0; i < tabWidget->count(); ++i)
    {
        SessionTabWidget* tab = qobject_cast<SessionTabWidget*>(tabWidget->widget(i));
        if (tab && tab->session() == sender())
            tabWidget->setTabEnabled(i, true);
    }
}

void MainWindow::disconnected()
{
    for (int i = 0; i < tabWidget->count(); ++i)
    {
        SessionTabWidget* tab = qobject_cast<SessionTabWidget*>(tabWidget->widget(i));
        if (tab && tab->session() == sender())
            tabWidget->setTabEnabled(i, false);
    }
}

void MainWindow::zoomIn()
{
    SessionTabWidget* tab = qobject_cast<SessionTabWidget*>(tabWidget->widget(0));
    if (tab)
    {
        tab->zoomIn();
        setZoomLevel(tab->zoomLevel());
    }
}

void MainWindow::zoomOut()
{
    SessionTabWidget* tab = qobject_cast<SessionTabWidget*>(tabWidget->widget(0));
    if (tab)
    {
        tab->zoomOut();
        setZoomLevel(tab->zoomLevel());
    }
}

void MainWindow::setZoomLevel(int level)
{
    for (int i = 0; i < tabWidget->count(); ++i)
    {
        SessionTabWidget* tab = qobject_cast<SessionTabWidget*>(tabWidget->widget(i));
        if (tab)
            tab->setZoomLevel(level);
    }

    QSettings settings;
    settings.beginGroup("State");
    settings.setValue("zoom", level);
}

void MainWindow::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
{
    switch (reason)
    {
        case QSystemTrayIcon::DoubleClick:
            setVisible(!isVisible());
            break;
        case QSystemTrayIcon::Trigger:
            raise();
            activateWindow();
            break;
        default:
            break;
    }
}

void MainWindow::alert()
{
    if (!isActiveWindow())
    {
        trayIcon->alert();
        QApplication::alert(this);
    }
}
